﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;

using log4net;

using itk.cda;
using itk.cda.cdaclasses;
using itk.cda.constraints.templates;
using itk.cda.datatypes;
using itk.cda.oids;
using itk.cda.rim;
using itk.cda.vocabs;

namespace WindowsFormsApplication1
{
    public partial class Form2 : Form
    {
        // Create a logger for use in this class
        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private ClinicalDocument_POCD_MT010011GB01 doc;

        private string ExampleName;
        private string ExampleDirectory;

        public Form2()
        {
            InitializeComponent();
            ExampleName = "Example 01";
            ExampleDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\CDA API Examples\";

            if (!Directory.Exists(ExampleDirectory)) { Directory.CreateDirectory(ExampleDirectory); }

            label1.Text = "API Version : " + ClinicalDocument_POCD_MT010011GB01.GetApiVersionNumber();
            label2.Text = ExampleName;


        }

        private void button2_Click(object sender, EventArgs e)
        {
            // Structured Body

            makeCDA(true);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            makeCDA(false);
        }

        private void makeCDA(bool structuredText)
        {
            log.Info("Application -- Start");

            // Creating the document also defines all the fixed attributes as defined by the ITK specifications
            //
            doc = new ClinicalDocument_POCD_MT010011GB01();

            doc.SetDocumentType("163391000000107", "Discharge from inpatient care");
            doc.SetMessageType("POCD_MT010002UK01");

            doc.Id = Guid.NewGuid();
            doc.SetId = Guid.NewGuid();

            doc.SetTitle("NHS Continuing Healthcare Fast Track Tool");
            // Set the effective date & time for the document
            doc.SetEffectiveTime(new DateTime(2008, 12, 12, 12, 12, 0));

            // Set the CDA Confidentiality Code
            doc.SetConfidentialityCode("R");

            // Set the document version number
            doc.SetVersionNumber(1);

            // Add the mandatory classes first for CDA
            // Record Target
            addCDARecordTarget();

            // Set Author
            addCDAAuthorDeviceUniversal();
            addCDAAuthorWorkgroupUniversal();
            addCDAAuthorPersonUniversal();
            addCDAAuthorNonNamedPersonUniversal();

            // Set DataEnterer
            addCDADataEnterer();

            // Set Informant
            addCDAInformantRelatedEntity();
            addCDAInformantPersonWithOrganization();

            // Set Custodian
            addCDACustodianOrganization();

            // Set Recipients
            addCDARecipientOrganizationUniversal();
            addCDARecipientPersonUniversal();
            addCDARecipientWorkgroupUniversal();

            // Add Encompassing Encounter
            addCDAEncompassingEncounter();

            if (structuredText)
            {
                addCdaStructuredBody();
                log.Info("Application -- Serialise Structured Body");
                SerializeToXML(doc);
                log.Info("Application -- End");

                MessageBox.Show("CDA File Created", "CDA Creation", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                openFileDialog1.Filter = "PDF Documents Files (*.pdf)|*.pdf";
                openFileDialog1.Multiselect = false;
                openFileDialog1.FileName = "";

                openFileDialog1.InitialDirectory = ExampleDirectory;

                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    doc.AddNonXMLBody("application/pdf", openFileDialog1.FileName);

                    addCDAnonXMLBody();
                    log.Info("Application -- Serialise Non XML Body");
                    SerializeToXML(doc);
                    log.Info("Application -- End");

                    MessageBox.Show("CDA File Created", "CDA Creation", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
        }
        private void addCdaStructuredBody()
        {
            TextSection sTextDS1 = new TextSection();
            sTextDS1.Title = "DS 1";
            sTextDS1.Text = "<content>Some Text</content>";
            sTextDS1.Id = "E27F4264-C005-4BC3-BFA1-57C3E64B30B7";

            TP145207GB01_AuthorDeviceUniversal author = new TP145207GB01_AuthorDeviceUniversal();

            author.AddAuthorId(new HL7V3_II(HL7V3_NullType.NoInformation));
            author.SetManufacturerModelName(new HL7V3_SC("Motiva 2010"));
            author.SetSoftwareName(new HL7V3_SC("Software name goes here"));

            author.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "SITE1234");
            author.SetOrgName("Elmsall Telehealth Centre");
            sTextDS1.AddAuthor(author, new HL7V3_TS(DateTime.Now));


            TextSubSection sTextDS11 = new TextSubSection();
            sTextDS11.Title = "DS 1.1";
            sTextDS11.Text = "<content>Some Text</content>";
            sTextDS11.Id = "E27F4264-C005-4BC3-BFA1-57C3E64B30B7";

            sTextDS1.section.Add(sTextDS11);

            TextSubSection sTextDS111 = new TextSubSection();
            sTextDS111.Title = "DS 1.1.1";
            sTextDS111.Text = "<content>Some Deep Text</content>";
            sTextDS111.Id = "E27F4264-C005-4BC3-BFA1-000000000000";

            sTextDS11.section.Add(sTextDS111);

            doc.AddStructuredBody(sTextDS1);

            TextSection sTextDS2 = new TextSection();
            sTextDS2.Title = "DS2";
            sTextDS2.Text = "<content>Some Text beneath DS1 </content>";
            sTextDS2.Id = "E27F4264-C005-4BC3-BFA1-57C3E64B30B7";

            doc.AddStructuredBody(sTextDS2);


        }

        private void addCDAnonXMLBody()
        {
            doc.AddNonXMLBody("application/pdf", openFileDialog1.FileName);
        }

        #region Add RecordTarget
        private void addCDARecordTarget()
        {
            // Record Target is a templated part of the CDA model, and there is only a choice of one template.

            TP145201GB01_PatientUniversal rt = new TP145201GB01_PatientUniversal();

            rt.AddPatientId(RoleClass.ID_LOCAL_NUMBER, "L123456");
            rt.AddPatientId(RoleClass.ID_NHS_NUMBER_TRACED, "1234567891");

            rt.AddStructuredAddress(HL7V3_AD.ADDRESS_USE_HOME,
                    new string[] { "21 County Lodge", "Woodtown" },
                        "Cheshire",
                        "CH7 FS1",
                        null
                        );

            rt.AddStructuredAddress(HL7V3_AD.ADDRESS_USE_PHYSICAL_LOCATION,
                    new string[] { "The Woodtown Retirement Home", "23, Seawood Road", "Woodtown" },
                        "Cheshire",
                        "CH7 FS5",
                        new HL7V3_IVL_TS(
                            new HL7V3_TS(DateTime.Now),
                            new HL7V3_TS(DateTime.Now.Add(new TimeSpan(100, 100, 100)))
                        )
                        );

            rt.AddTelecom(HL7V3_TEL.TELECOM_USE_HOME, HL7V3_TEL.TelecomType.Telephone, "01433 745667");
            rt.AddTelecom(HL7V3_TEL.TELECOM_USE_HOME_VACATION, HL7V3_TEL.TelecomType.Telephone, "01433 631628");
            rt.AddTelecom(HL7V3_TEL.TELECOM_USE_HOME, HL7V3_TEL.TelecomType.Email, "belinda.taylor@emailfree.co.uk");

            // TODO - Is this required, for the template the patient class is mandatory, why not create it be default ?
            rt.SetPatientBirthTime(new HL7V3_TS(new DateTime(1969, 5, 19, 15, 45, 12)));
            rt.SetPatientGenderCode("1");  // TODO - For CNE vocabs - should it use ENUMs ?

            //HL7V3_PN patient_name_1 = new HL7V3_PN();
            //patient_name_1.SetUnstructuredName("Alison Smith");
            //rt.SetPatientName(patient_name_1);

            HL7V3_PN patient_name_2 = new HL7V3_PN();
            patient_name_2.SetStructuredName("Mr", new string[] { "Richard", "Mark" }, "Kavanagh", "III");
            patient_name_2.SetNameUse(HL7V3_PN.NAME_USE_PREFERRED);
            patient_name_2.SetTimePeriod(
                new HL7V3_TS(DateTime.Now),
                new HL7V3_TS(DateTime.Now.Add(new TimeSpan(100, 100, 100)))
                );
            rt.SetPatientName(patient_name_2);
            rt.SetPatientLanguageCode("en");

            // rt.PatientRole.AddOrganisation();
            rt.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "V396F");
            rt.SetOrgName("Northgate Medical Practice");
            rt.AddOrgTelecom(HL7V3_TEL.TELECOM_USE_WORK_PLACE, HL7V3_TEL.TelecomType.Telephone, "01433 111222");

            rt.SetOrgStructuredAddress(HL7V3_AD.ADDRESS_USE_WORK_PLACE,
        new string[] { "Springer Street" },
            "Cheshire",
            "CH12 5TY"
            );

            doc.AddRecordTarget(rt);
        }
        #endregion

        #region Add Custodian
        private void addCDACustodianOrganization()
        {
            TP145018UK03_CustodianOrganizationUniversal custodian = new TP145018UK03_CustodianOrganizationUniversal();

            custodian.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "5L3");
            custodian.SetOrgName("Medway NHS Foundation Trust");

            doc.AddCustodian(custodian);

        }

        #endregion

        #region Add Informant

        private void addCDAInformantPersonWithOrganization()
        {
            TP145210GB01_PersonWithOrganizationUniversal informant = new TP145210GB01_PersonWithOrganizationUniversal();

            informant.AddId("1.2.826.0.1285.0.2.0.67", "102018559987");
            informant.SetJobRoleCode("2.16.840.1.113883.2.1.3.2.4.17.124", "NR0620", "Staff Nurse", HL7V3_CV.flavorTypes.CodedPlain);
            informant.SetStructuredAddress(HL7V3_AD.ADDRESS_USE_PHYSICAL_LOCATION,
                    new string[] { "The Groves", "Sycamore Avenue", "Treesville" },
                        "Cheshire",
                        "CH7 5TY",
                        new HL7V3_IVL_TS(
                            new HL7V3_TS(DateTime.Now),
                            new HL7V3_TS(DateTime.Now.Add(new TimeSpan(200, 100, 100)))
                        )
                        );
            informant.AddTelecom(HL7V3_TEL.TELECOM_USE_HOME, HL7V3_TEL.TelecomType.Email, "june.bradwick@emailfree.co.uk");

            HL7V3_PN this_name = new HL7V3_PN();
            this_name.SetStructuredName(null, new string[] { "Steve" }, "Cook", null);
            informant.SetPersonName(this_name);

            informant.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "RX8");
            informant.SetOrgName("Yorkshire Ambulance Service Trust");

            doc.AddInformant(informant);
        }
        private void addCDAInformantRelatedEntity()
        {
            TP145007UK03_RelatedEntity informant = new TP145007UK03_RelatedEntity();

            informant.SetPersonRelationTypeCode("01", "Spouse");
            informant.SetTelecom(HL7V3_TEL.TELECOM_USE_HOME, HL7V3_TEL.TelecomType.Email, "test.email@emailfree.co.uk");
            HL7V3_PN this_name = new HL7V3_PN();
            this_name.SetStructuredName("Dr", new string[] { "Sarah" }, "Cook", null);
            informant.SetPersonName(this_name);

            informant.SetStructuredAddress(HL7V3_AD.ADDRESS_USE_PHYSICAL_LOCATION,
        new string[] { "The Groves", "Sycamore Avenue", "Treesville" },
            "Cheshire",
            "CH7 5TY",
            new HL7V3_IVL_TS(
                new HL7V3_TS(DateTime.Now),
                new HL7V3_TS(DateTime.Now.Add(new TimeSpan(200, 100, 100)))
            )
            );


            doc.AddInformant(informant);
        }
        #endregion

        #region Add DateEnterer
        private void addCDADataEnterer()
        {
            TP145205GB01_PersonUniversal de = new TP145205GB01_PersonUniversal();

            de.AddId("2.16.840.1.113883.2.1.3.2.4.18.24", "100");

            HL7V3_PN this_name = new HL7V3_PN();
            this_name.SetStructuredName(null, new string[] { "Steve" }, "Cook", null);
            de.SetPersonName(this_name);


            de.AddTelecom(HL7V3_TEL.TELECOM_USE_HOME, HL7V3_TEL.TelecomType.Email, "steve.cook@freemail.co.uk");
            doc.AddDataEnterer(de);
        }
        #endregion

        #region Add IntendedRecipients
        private void addCDARecipientOrganizationUniversal()
        {
            TP145203GB02_RecipientOrganizationUniversal rec = new TP145203GB02_RecipientOrganizationUniversal();

            rec.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "EM396");
            rec.SetOrgName("Medway Kent Ambulance Trust");
            rec.SetIndustryCode("001", "General Medical Practice");

            doc.AddPrimaryInformationRecipient(rec);
        }

        private void addCDARecipientPersonUniversal()
        {
            TP145202GB01_RecipientPersonUniversal rec = new TP145202GB01_RecipientPersonUniversal();

            rec.SetJobRoleCode("NR0260", "General Medical Practitioner");
            rec.AddId(new HL7V3_II(HL7V3_NullType.NoInformation));

            HL7V3_PN name = new HL7V3_PN();
            name.SetStructuredName("", new string[] { "Pauline" }, "Shelley", "");

            rec.SetPersonName(name);


            rec.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "W123");
            rec.SetOrgName("Medway Medical Practice");
            rec.SetIndustryCode("001", "General Medical Practice");

            doc.AddTrackerInformationRecipient(rec);
        }

        private void addCDARecipientWorkgroupUniversal()
        {
            TP145204GB02_RecipientWorkgroupUniversal rec = new TP145204GB02_RecipientWorkgroupUniversal();

            rec.AddId(new HL7V3_II(HL7V3_NullType.NoInformation));
            rec.AddTelecom(HL7V3_TEL.TELECOM_USE_HOME, HL7V3_TEL.TelecomType.Email, "june.bradwick@emailfree.co.uk");
            rec.SetWorkgroupRoleCode(OIDStore.OIDWorkgroupRoleName, "NR0260", "General Medical Practitioner", HL7V3_CV.flavorTypes.CodedPlain);

            HL7V3_PN name = new HL7V3_PN();
            name.SetStructuredName("", new string[] { "Pauline" }, "Shelley", "");
            rec.SetPersonName(name);

            rec.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "W123");
            rec.SetOrgName("Medway Medical Practice");

            doc.AddTrackerInformationRecipient(rec);
        }
        #endregion

        #region Add Authors
        private void addCDAAuthorDeviceUniversal()
        {
            TP145207GB01_AuthorDeviceUniversal author = new TP145207GB01_AuthorDeviceUniversal();

            author.AddAuthorId(new HL7V3_II(HL7V3_NullType.NoInformation));
            author.SetManufacturerModelName(new HL7V3_SC("Motiva 2010"));
            author.SetSoftwareName(new HL7V3_SC("Software name goes here"));

            author.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "SITE1234");
            author.SetOrgName("Elmsall Telehealth Centre");



            doc.AddAuthor(author, new HL7V3_TS(new DateTime(2009, 01, 04, 00, 01, 0, 0), HL7V3_TS.flavors.YYYYMMDDHHMM));
        }

        private void addCDAAuthorWorkgroupUniversal()
        {
            TP145212GB02_WorkgroupUniversal author = new TP145212GB02_WorkgroupUniversal();
            author.AddWorkgroupId("1.2.826.0.1285.0.2.0.109", "102016309999");
            author.SetWorkgroupCode("2.16.840.1.113883.2.1.3.2.4.17.266", "01", "CHC Team", HL7V3_CV.flavorTypes.CodedPlain);

            author.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "V396AA");
            author.SetOrgName("East Cheshire NHS Trust");

            HL7V3_PN author_name = new HL7V3_PN();
            author_name.SetStructuredName("Mrs", new string[] { "Jessica" }, "Brown", null);
            // author.SetPersonName(author_name);

            doc.AddAuthor(author, new HL7V3_TS(new DateTime(2010, 10, 30, 15, 15, 0, 0), HL7V3_TS.flavors.YYYYMMDDHHMM));
        }
        private void addCDAAuthorNonNamedPersonUniversal()
        {
            TP145208GB01_AuthorNonNamedPersonUniversal author = new TP145208GB01_AuthorNonNamedPersonUniversal();

            author.AddAuthorId(new HL7V3_II(HL7V3_NullType.NoInformation));
            author.SetAuthorCode("2.16.840.1.113883.2.1.3.2.4.17.124", "NR0620", "Staff Nurse", HL7V3_CV.flavorTypes.CodedPlain);

            author.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "V396");
            author.SetOrgName("East Cheshire NHS Trust");

            doc.AddAuthor(author, new HL7V3_TS(new DateTime(2010, 10, 20, 15, 15, 0, 0), HL7V3_TS.flavors.YYYYMMDDHHMM));
        }
        private void addCDAAuthorPersonUniversal()
        {
            TP145200GB01_AuthorPersonUniversal author = new TP145200GB01_AuthorPersonUniversal();


            author.AddAuthorId(new HL7V3_II(HL7V3_NullType.NoInformation));
            author.SetAuthorCode("2.16.840.1.113883.2.1.3.2.4.17.124", "NR0620", "Staff Nurse", HL7V3_CV.flavorTypes.CodedPlain);

            HL7V3_PN author_name = new HL7V3_PN();
            author_name.SetStructuredName("Mrs", new string[] { "June" }, "Bradwick", null);
            author.SetPersonName(author_name);
            author.AddTelecom(HL7V3_TEL.TELECOM_USE_HOME, HL7V3_TEL.TelecomType.Email, "june.bradwick@emailfree.co.uk");

            author.AddStructuredAddress(HL7V3_AD.ADDRESS_USE_PHYSICAL_LOCATION,
                    new string[] { "The Groves", "Sycamore Avenue", "Treesville" },
                        "Cheshire",
                        "CH7 5TY",
                        new HL7V3_IVL_TS(
                            new HL7V3_TS(DateTime.Now),
                            new HL7V3_TS(DateTime.Now.Add(new TimeSpan(200, 100, 100)))
                        )
                        );


            author.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "V396");
            author.SetOrgName("East Cheshire NHS Trust");

            doc.AddAuthor(author, new HL7V3_TS(new DateTime(2010, 10, 20, 15, 15, 0, 0), HL7V3_TS.flavors.YYYYMMDDHHMM));
        }
        #endregion

        #region Add EncompassingEncounter
        private void addCDAEncompassingEncounter()
        {


            TP146228GB01_EncompassingEncounter ee = new TP146228GB01_EncompassingEncounter();

            //
            // Populate the entry class
            //
            Guid instanceId = Guid.NewGuid();

            ee.AddId(instanceId.ToString().ToUpper());
            ee.SetCode("2.16.840.1.113883.2.1.3.2.4.15", "11429006", "Consultation", HL7V3_CV.flavorTypes.CodedPlain);

            HL7V3_TS timeStart = new HL7V3_TS(new DateTime(2011, 05, 19, 19, 45, 0), HL7V3_TS.flavors.YYYYMMDDHHMM);
            HL7V3_TS timeEnd = new HL7V3_TS(new DateTime(2011, 05, 19, 20, 15, 0), HL7V3_TS.flavors.YYYYMMDDHHMM);
            ee.SetEffectiveTime(timeStart, timeEnd);
            ee.SetDischargeDispositionCode(HL7V3_NullType.NotApplicable);

            //
            // Populate the location participation
            //
            TP145211GB01_HealthCareFacilityUniversal hcf = new TP145211GB01_HealthCareFacilityUniversal();
            hcf.SetCareSettingTypeCode("2.16.840.1.113883.2.1.3.2.4.15", "394780001", "Ward on NHS hospital site", HL7V3_CV.flavorTypes.CodedPlain);

            hcf.SetLocationName("Place Name Here");
            hcf.SetLocationAddress(HL7V3_NullType.NotApplicable);

            hcf.SetSPOId("2.16.840.1.113883.2.1.3.2.4.19.1", "RFM");
            hcf.SetSPOName("Hebburn NHS Trust");
            ee.SetLocationTemplate(hcf);

            //
            // Populate the responsibleParty 

            TP145212GB02_WorkgroupUniversal respParty01 = new TP145212GB02_WorkgroupUniversal();
            respParty01.AddWorkgroupId("1.2.826.0.1285.0.2.0.109", "102016309999");
            respParty01.SetWorkgroupCode("2.16.840.1.113883.2.1.3.2.4.17.266", "01", "CHC Team", HL7V3_CV.flavorTypes.CodedPlain);

            respParty01.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "V396AA");
            respParty01.SetOrgName("East Cheshire NHS Trust");

            HL7V3_PN author_name = new HL7V3_PN();
            author_name.SetStructuredName("Mrs", new string[] { "Jessica" }, "Brown", null);

            ee.SetResponsiblePartyTemplate(respParty01);

            #region ResponsibleParty TP145210GB01_PersonWithOrganizationUniversa
            TP145210GB01_PersonWithOrganizationUniversal respParty02 = new TP145210GB01_PersonWithOrganizationUniversal();

            respParty02.AddId("1.2.826.0.1285.0.2.0.67", "102018559987");
            respParty02.SetJobRoleCode("2.16.840.1.113883.2.1.3.2.4.17.124", "NR0620", "Staff Nurse", HL7V3_CV.flavorTypes.CodedPlain);
            respParty02.SetStructuredAddress(HL7V3_AD.ADDRESS_USE_PHYSICAL_LOCATION,
                    new string[] { "The Groves", "Sycamore Avenue", "Treesville" },
                        "Cheshire",
                        "CH7 5TY",
                        new HL7V3_IVL_TS(
                            new HL7V3_TS(DateTime.Now),
                            new HL7V3_TS(DateTime.Now.Add(new TimeSpan(200, 100, 100)))
                        )
                        );
            respParty02.AddTelecom(HL7V3_TEL.TELECOM_USE_HOME, HL7V3_TEL.TelecomType.Email, "june.bradwick@emailfree.co.uk");

            HL7V3_PN this_name = new HL7V3_PN();
            this_name.SetStructuredName(null, new string[] { "Steve" }, "Cook", null);
            respParty02.SetPersonName(this_name);

            respParty02.SetOrgId("2.16.840.1.113883.2.1.3.2.4.19.1", "RX8");
            respParty02.SetOrgName("Yorkshire Ambulance Service Trust");
            ee.SetResponsiblePartyTemplate(respParty02);
            #endregion
            //
            doc.AddEncompassingEncounter(ee);
        }
        #endregion

        public void SerializeToXML(ClinicalDocument_POCD_MT010011GB01 doc)
        {
            doc.CreateXML(ExampleDirectory + ExampleName + @".xml");
        }
    }
}